/*	
 * Authors: Ken YANG <spng.yang@gmail.com>
 * 	
 * Mammoth client main program
 *
 * Copyright (C) 2007-2008 Ken YANG
 * This program is free software; you can redistribute it and/or 
 * modify it under the terms of the GNU General Public License 
 * as published by the Free Software Foundation, version 2. 
 * THIS SOFTWARE COMES "AS IS" WITHOUT ANY WARRANTIES.
 */

#if !defined (_HAVE_NET_BASIC_H)
#define _HAVE_NET_BASIC_H 1

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include "error.h"
#include <netdb.h>
#include "func_basic.h"
#include <fcntl.h>
#include <net/if.h>



#define SERV_PORT 9877
/* 
 * Following could be derived from SOMAXCONN in <sys/socket.h>, 
 * but many kernels still #define it as 5, while actually 
 * supporting many more 
 * */
#define	LISTENQ		1024	/* 2nd argument to listen() */


/* for code convience */
typedef struct sockaddr *SA;

#define IF_NAME 16	/* same as IFNAMSIZ in <net/if.h> */
#define IF_HADDR 8	/* allow for 64-bit EUI-64 in future */

/* Data structure for interface */
struct if_info{
	char if_name[IF_NAME];	/* interface name, null-terminated */
	short if_index;	/* interface index */
	short if_mtu;	/* interface mtu */
	u_char if_haddr[IF_HADDR];	/* Hardware address */
	u_short if_hlen;	/* bytes in hardware address:0, 6, 8 */
	short if_flags;	/* IFF_xxx constats from <net/if.h> */
	short if_myflags;	/* our own IFI_xxx flags */
	struct sockaddr *if_addr;	/* primary address */
	struct sockaddr *if_brdaddr;	/* broadcast address */
	struct sockaddr *if_dstaddr;	/* destination address */
	struct if_info *if_next;	/* next of these structures */
};

#define IF_ALIAS 1	/* if_addr is an alias */


/* Wrapper of socket, including error handle */
int Socket(int family, int type, int protocol);

/* Same with Socket */
void Connect(int sockfd, const SA serv_addr, socklen_t addrlen);
void Bind(int sockfd, const SA my_addr, socklen_t addrlen);
void Listen(int sockfd, int backlog);
int Accept(int sockfd, SA addr, socklen_t *addrlen);
void Close(int sockfd);
void Getsockname(int sockfd, SA localaddr, socklen_t *addrlen);
void Getpeername(int sockfd, SA peeraddr, socklen_t *addrlen);
void Inet_pton(int family, const char *strptr, void *addrptr);
void Shutdown(int sockfd, int howto);
ssize_t Recvfrom(int sockfd, void *buf, size_t nbytes, int flags,
		SA from, socklen_t *addrlen);
ssize_t Sendto(int sockfd, void *buf, size_t nbytes, int flags,
		const SA to, socklen_t addrlen);
void Setsockopt(int sockfd, int level, int optname, void *optval,
		socklen_t *optlen);
void Getsockopt(int sockfd, int level, int optname, void *optval,
		socklen_t *optlen);

/* Get the protocol family of a socket */
int sockfd_to_family(int sockfd);
/* Above's wrapper */
int Sockfd_to_family(int sockfd);

/* create tcp socket and connect to a server */
int tcp_connect(const char *hostname, const char *service);

/* 
 * create tcp socket, bind and listen 
 * "addrlenp" parameter can be NULL, which mean we don't need 
 * the sockaddr size, if not NULL, we use "addrlenp" return the 
 * size of sockaddr
 * */
int tcp_listen(const char *hostname, const char *service, 
		socklen_t *addrlenp);

/* 
 * create unconnected udp socket 
 * 
 * NOTE:
 * Allocate space for "sa", caller must free this space
 *
 * */
int udp_unconnect(const char *host, const char *service,
		struct sockaddr **sa, socklen_t *lenp);

/* create connected udp socket */
int udp_connect(const char *host, const char *service);

/* create udp socket for server, including bind */
int
udp_server(const char *host, const char *serv, socklen_t *addrlenp);

/* 
 * connect with timeout, for the timeout of 
 * tcp is too long 
 *
 * Parameter:
 *
 * first three: same with "real" connect
 * last one: the seconds of timeout
 * */
int connect_timeout(int sockfd, const SA sa, socklen_t salen,
		int nsec);


/* 
 * connect nonblock version
 *
 * Parameter:
 *
 * first three: same with "real" connect
 * last one: the seconds waiting for finishing connection
 * */
int connect_nonb(int sockfd, const SA sa, socklen_t salen, int nsec);

/*
 * There is no easy way to pass back the integer return code from
 * getaddrinfo() in the function above, short of adding another argument
 * that is a pointer, so the easiest way to provide the wrapper function
 * is just to duplicate the simple function as we do here.
 * */
struct addrinfo *
Host_serv(const char *host, const char *serv, int family, int socktype);

/* 
 * Because inet_ntop must speicific address of socket structure, 
 * we have to call inet_ntop with different options for various 
 * address family. 
 *
 * So we define sock_ntop(), sock_ntop_host(), and etc to avoid 
 * this problem.
 * */
char *
sock_ntop(const struct sockaddr *sa, socklen_t salen);
char *
Sock_ntop(const struct sockaddr *sa, socklen_t salen);

/* 
 * convert the "host part of sockaddr to presentation, without 
 * port.
 * */
char *
sock_ntop_host(const struct sockaddr *sa, socklen_t salen);
char *
Sock_ntop_host(const struct sockaddr *sa, socklen_t salen);

/* as function name said */
int sock_get_port(const struct sockaddr *sa, socklen_t salen)

#endif

